﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Miris.HumanMilkAnalyser.DataModel;
using Miris.HumanMilkAnalyser.Repository.Interface;
using Miris.HumanMilkAnalyser.Service.Interface;
using Miris.HumanMilkAnalyser.Service.Shared;
using Miris.HumanMilkAnalyser.Service.Validation;

namespace Miris.HumanMilkAnalyser.Service
{
    public class UnassignedSampleNumberService : ServiceBase<UnassignedSampleNumber>, IUnassignedSampleNumberService
    {
        public UnassignedSampleNumberService(IRepositoryFactory repositoryFactory) : base(repositoryFactory, new UnassignedSampleNumberValidator()) { }

        /// <summary>
        /// Get the generated sample number based on configured rule.
        /// </summary>
        /// <returns>The generated sample number meets configured rule.</returns>
        public string GetSampleNumber()
        {
            var numberHelper = new ConfiguredNumberHelper(ConfigurationConstant.SampleNumberPrefix,
                ConfigurationConstant.SampleNumberContainsYear,
                ConfigurationConstant.SampleNumberContainsMonth,
                ConfigurationConstant.SampleNumberContainsDay,
                ConfigurationConstant.SampleNumberInitializedSequence);

            var number = string.Empty;

            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();
                var unassignedSampleNumberRepository = RepositoryFactory.CreateUnassignedSampleNumberRepository();
                var analysisResultRepository = RepositoryFactory.CreateAnalysisResultRepository();

                // Get current max unassigned sample number based on provided full prefix.
                var currentMaxUnassignedSampleNumber = GetCurrentMaxUnassignedSampleNumber(unassignedSampleNumberRepository, numberHelper);

                // Get current max assigned sample number based on provided full prefix.
                var currentMaxAssignedSampleNumber = GetCurrentMaxAssignedSampleNumber(analysisResultRepository, numberHelper);

                string currentMaxSampleNumber = string.Empty;

                if (currentMaxUnassignedSampleNumber != null &&
                    currentMaxAssignedSampleNumber == null)
                {
                    currentMaxSampleNumber = currentMaxUnassignedSampleNumber.SampleNumber;
                }
                else if (currentMaxUnassignedSampleNumber == null &&
                    currentMaxAssignedSampleNumber != null)
                {
                    currentMaxSampleNumber = currentMaxAssignedSampleNumber.SampleNumber;
                }
                else if (currentMaxUnassignedSampleNumber != null &&
                    currentMaxAssignedSampleNumber != null)
                {
                    currentMaxSampleNumber = int.Parse(currentMaxUnassignedSampleNumber.SampleNumber.Replace(numberHelper.FullPrefix, string.Empty)) > 
                        int.Parse(currentMaxAssignedSampleNumber.SampleNumber.Replace(numberHelper.FullPrefix, string.Empty)) ? 
                        currentMaxUnassignedSampleNumber.SampleNumber : currentMaxAssignedSampleNumber.SampleNumber;
                }

                // Get the new generated sample number.
                number = numberHelper.GenerateNewNumber(currentMaxSampleNumber);

                // Add this sample number into UnassignedSampleNumber table.
                unassignedSampleNumberRepository.Add(new UnassignedSampleNumber
                {
                    SampleNumber = number,
                    GenerateDate = GeneralUtility.GetCurrentDateTime()
                });

                // Commit this change.
                RepositoryFactory.Commit();
            }

            return number;
        }

        private UnassignedSampleNumber GetCurrentMaxUnassignedSampleNumber(IUnassignedSampleNumberRepository unassignedSampleNumberRepository, 
            ConfiguredNumberHelper numberHelper)
        {
            var matchedUnassignedSampleNumbers = unassignedSampleNumberRepository.Query(p => p.SampleNumber.Length == numberHelper.FixedLength);

            if (!string.IsNullOrEmpty(numberHelper.FullPrefix))
            {
                // If contains prefix.

                matchedUnassignedSampleNumbers = matchedUnassignedSampleNumbers.Where(p => p.SampleNumber
                    .StartsWith(numberHelper.FullPrefix));
            }

            // Get current max unassigned sample number based on provided full prefix.
            return matchedUnassignedSampleNumbers.OrderByDescending(p => p.SampleNumber).Take(1).FirstOrDefault();
        }

        private AnalysisResult GetCurrentMaxAssignedSampleNumber(IAnalysisResultRepository analysisResultRepository, ConfiguredNumberHelper numberHelper)
        {
            var matchedAssignedSampleNumbers = analysisResultRepository.Query(p => p.SampleNumber.Length == numberHelper.FixedLength);

            if (!string.IsNullOrEmpty(numberHelper.FullPrefix))
            {
                // If contains prefix.

                matchedAssignedSampleNumbers = matchedAssignedSampleNumbers.Where(p => p.SampleNumber
                    .StartsWith(numberHelper.FullPrefix));
            }

            // Get current max unassigned sample number based on provided full prefix.
            return matchedAssignedSampleNumbers.OrderByDescending(p => p.SampleNumber).Take(1).FirstOrDefault();
        }
    }
}
